#include "Channel.hpp"
#include "Task.hpp"
#include <vector>
#include <functional>


#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

// 包装器
using work_t = function<void()>;
enum
{
    OK = 0,
    USEERROR,
    PIPEERROR,
    FORKERROR
};

class ProcessPool
{
public:
    ProcessPool(int processNum, work_t work)
        : num(processNum), Worker(work)
    {}
    ~ProcessPool()
    {}

    int InitProcessPoll()
    {
        // 2. 创建指定个进程
        for (int i = 0; i < num; i++)
        {
            // 1.先创建管道
            int pipefd[2] = {0}; // 返回的两个文件描述符，指向同一个管道
            int n = ::pipe(pipefd);

            if (n == -1)
                return PIPEERROR;

            pid_t id = fork();
            if (id < 0)
                return FORKERROR;

            if (id == 0)
            {
                // 子进程关闭写端
                ::close(pipefd[1]);

                // 子进程要关闭 从父进程继承下来的之前的管道
                if (i > 0)
                {
                    // cout << "child " << getpid() << " shut history fd" << endl;
                    for (auto &c : channels)
                    {
                        // cout << c.Get_wfd() << " ";
                        c.Close();
                    }
                    // cout << endl;
                }

                // 执行任务
                dup2(pipefd[0], 0); // 让所有的子进程都从0里读，无需再传递管道的fd
                Worker();
                exit(0);
            }

            // 父进程关闭读端
            ::close(pipefd[0]);
            channels.emplace_back(pipefd[1], id);
        }
        return OK;
    }

    void DispatchTask()
    {
        int process = 0;
        int sum = 20;
        while (sum--)
        {
            // a. 选择任务，一个整数
            int task = taskManeger.Select();
            // b. 轮循选择一个子进程/管道
            Channel &cur = channels[process++];
            process %= channels.size();

            cout << "-------------------------------" << endl;
            cout << "send " << task << "to " << cur.GetName() << " 剩余任务：" << sum << endl;
            cout << "-------------------------------" << endl;

            // c. 给子进程 派发任务(向相应的管道中写)
            cur.Send(task);

            sleep(1);
        }
    }

    void ClearProcessPool()
    {
        for (auto &c : channels)
        {
            c.Close();
            pid_t rid = waitpid(c.GetPid(), nullptr, 0);
            if (rid > 0)
            {
                cout << "father wait pid:" << rid << " success" << endl;
            }
        }
    }

    // void Debug(vector<Channel> &channels)
    // {
    //     for (auto &c : channels)
    //     {
    //         cout << "pipe name:" << c.GetName() << endl;
    //     }
    // }

private:
    vector<Channel> channels;
    int num;
    work_t Worker;
};
